perm filename MCTRST.PUB[HAL,HE] blob sn#133594 filedate 1974-12-04 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00008 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	.NEWSS CONTROL STRUCTURES
C00009 00003	.cob:NEWSSS COBEGIN-COEND
C00011 00004	.tsk:NEWSSS PARTIAL ORDERING OF SUBTASKS
C00015 00005	.evt:NEWSSS EVENTS:  SIGNAL AND WAIT
C00018 00006	.NEWSSS STATEMENT CONDITION MONITORS
C00021 00007	.NEWSSS	COMMENTS
C00026 00008	.NEWSSS	PROCEDURES
C00033 ENDMK
C⊗;
.NEWSS CONTROL STRUCTURES

.NEWSSS TRADITIONAL STRUCTURES

	AL has many of the traditional Algol control structures,
including %4statements%*, %4blocks%*, %4conditionals%*, and
%4loops%*.  There are no %4jumps%* in AL, because they confuse the
flow analysis needed for maintaining planning values and because it
is possible to accomplish much without them. 

	We have already seen some applications of block structure.
More formally, a
%4block%* is a list of %4statements%*, separated by semicolons, and
surrounded by the reserved words %4BEGIN%* and %4END%*.  The entire
block is treated syntactically as a statement; thus, its definition
is recursive.  One particular kind of statement is the
%4declaration%*.  We have already seen declarations for algebraic
variables.  There are a few rules pertaining to variables and
declarations: Every variable must be declared at some point in the
program before it is used.  Declarations may appear anywhere in a
block; there is no restriction that they must precede other
statements.  The %4local block%* of a variable is the block defined
by the narrowest BEGIN-END pair which surrounds its declaration.
Blocks defined by narrower BEGIN-END pairs are called %4inner
blocks%*, and those defined by wider pairs are called %4global
blocks%*.  The primary rule is that variables may only be referenced
in their own local or inner blocks.  Another way to state the same
thing is that within any given block, it is only legal to refer to
variables declared locally or globally to that block. 


Here is a simple example which demonstrates the other standard ALGOL
control structures:
.UNFILL
sample:	BEGIN  α{%4Meaningless example%*α}
	SCALAR a, i;
	a ← 2;
	FOR i ← 1 STEP 1 UNTIL 10 DO a ← a*a;
.comt 12
	α{This is very likely to cause arithmetic overflow!α}
.end
	WHILE a > 0 DO
	loop:	BEGIN 
		a ← a - 1;
		IF a < 5 THEN WRITE(a) ELSE WRITE(a-5)
		END loop;
	WRITE("Done")
	END sample
.REFILL
Even though there is no jump instruction, there are labels; they
are useful during debugging, for naming condition
monitors, and for some other purposes which we will see later.
It is good practice to name blocks, and to repeat the name after the
closing END; this allows the compiler to check that the proper
BEGINs and ENDs match.

The %4FOR loop%* is quite traditional; it follows the form:
.UNFILL
	FOR <s var> ← <s expr> STEP <s expr> UNTIL <s expr> DO <statement>
.REFILL
where <s var> stands for "(possibly dimensioned) scalar variable" and
<s expr> stands for "scalar expression of compatible dimension".  The
initial value of the variable is the value of the first expression;
every time the statement is executed, its value is incremented by the
value of the second expression, and the process repeats until the
value exceeds that of the third expression.  If the step size is
negative, the right things happen.  A test is made before the first
iteration, so it is possible that the loop will not get executed at
all. 

The %4WHILE loop%* is another means to control iteration.  It syntax is this:
.UNFILL
	WHILE <condition> DO <statement>
.REFILL
where the condition is some boolean expression involving one of the
operators <, >, ≤, ≥, =, and ≠.  Boolean
expressions can be built up out of such arithmetic operators, the logical
connectives %4∧ (and), ∨ (or), ¬ (not)%*, and the logical constants
%4true%* and %4false%*.
  The first check is made before the first
iteration; the statement is executed repeatedly until the condition fails.

The %4conditional statement%* has the form:
.unfill
	IF <condition> 
		THEN <statement>
		ELSE <statement>
.refill
The ELSE part is optional.  The <condition>, which is just like the
condition in a WHILE statement, is evaluated; if it is %4true%*, the
THEN part will get executed; if it is %4false%*, the ELSE part (if there
is one) gets executed.  

The %4conditional expression%* is much the same as the conditional
statement:
.unfill
	IF <condition> 
		THEN <expression>
		ELSE <expression>
.refill
This can be used whenever an expression is needed.

.cob:NEWSSS COBEGIN-COEND

	In addition to traditional ALGOL structures, there are also
some additional ones for more sophisticated flow of control.  The first such
construct is the %4COBEGIN-COEND%* pair, which brackets statements
whose execution is meant to occur independently.  Each of the
statements within the %4simultaneous%* block will eventually get executed, but
there may be considerable overlap of execution.  For example, while
one arm is moving, another statement can be computing; several arms
can also work at the same time. The termination of the 
block occurs only when all of the statements in the scope of the
COBEGIN have terminated.  Declarations should not be included as local
statements in the region of simultaneity.  It is not particularly
useful to have simultaneous execution of a purely computational code;
the real reason for the COBEGIN construct is to allow simultaneous
independent manipulator control.  Here is a simple example:
.UNFILL
swing:	COBEGIN  α{%4Wish to get all three arms to their rest positions.%*α}
	MOVE yellow TO ypark;

	MOVE blue TO bpark;

	MOVE red α{%4we should have such an arm%*α} TO rpark;
	COEND swing
.REFILL

.tsk:NEWSSS PARTIAL ORDERING OF SUBTASKS

	An assembly task is often divided into  subtasks which enjoy a
partial ordering with  respect to the intended order of execution.  
For example, consider
a task A which contains four subtasks, B, C, D, and E, of which B and
C must  be done before D,  and D must be  done before E, but  B and C
could  be done  in any  order.  It  is possible  in AL  to leave the
ordering of  the  subtasks up  to  the compiler,  which will  try  to
optimize the entire  operation
with respect to total expected time and economy of motion.
For example,
.UNFILL
     a:	TASK BEGIN α{%4Sample of partial ordering on subtasks%*α}
	     b:	BEGIN 
		<code for task B>
		END b;

	     c:	<code for task C>;

	   d_e:	BEGIN α{%4both D and E%*α}
		<code for task D>
		<code for task E>
		END d_e;

	PREREQUISITE OF d_e IS c;
	PREREQUISITE OF d_e IS b;
	END 
.REFILL

	The words TASK BEGIN introduce a  %4task block%*, which contains
a  set of statements.  The prerequisite statement
.unfill
	PREREQUISITE OF <label 1> IS <label 2>
.refill
informs the compiler that the statement identified by <label 2> must
be done before the statement identified by <label 1>.  One important
restriction is that both statements so named, as well as the prerequisite
statement itself, must all occur in the same TASK block.

	The order in which the statements are performed is determined
only insofar as the prerequisite conditions demand.  The compiler may
reorder them consistently with  the preconditions, and may even execute
some of the statements simultaneously  (as if there were a  COBEGIN),
if this is feasible.

	As can be expected, it is rather difficult for the compiler
to keep track of planning values in the vicinity of a TASKBEGIN.  For
this reason, it is a good idea to make heavy use of the planning
value assignment statement (the one with the double arrow: "α←α←"; see 
{ssref pvs})
to keep the compiler informed of what is intended to be true, both
within the partially ordered block and immediately afterwards.

.evt:NEWSSS EVENTS:  SIGNAL AND WAIT

	To  achieve simultaneous  coordinated  motion,   one  uses  a
special  form of  the move  commands which  will be  discussed later.
However, some  simple  synchronization  is  possible within  the  context  of
simultaneous  execution.   This  is  achieved  by means  of  explicit
events,  which can be signaled and awaited.   Every different event
that the user wishes to use should be  declared.  For instance,
.UNFILL
	EVENT e1, e2, e3     .
.REFILL
With each event is associated a count of how many times it has been signalled.
Initially, the count is 0, that is, no  signals have appeared,
and no process is waiting.  The statement
.UNFILL
	SIGNAL e1
.REFILL
increments the count associated  with event e1, and if  the resulting
count  is 0  or negative, one  of those  processes waiting for  e1 is
released from its wait and readied for execution.  The statement
.UNFILL
	WAIT e1
.REFILL
decrements the count associated  with event E1, and if the resulting
count  is negative,  the  process issuing  the WAIT  is  blocked from
continuing until  a  signal  comes along.    If  the count  is  0  or
positive, there is no waiting.

	An  example of  the utility  of  this construct  is inside  a
simultaneous  block, where one  path of execution requires  that the other
path has passed some milestone.  Here is how such a use might appear:
.UNFILL
	EVENT milestone;
	COBEGIN α{%4Example of use of SIGNAL and WAIT%*α}
	 path1:	BEGIN 
		<code before the critical point>
		WAIT milestone;
		<code after the critical point>
		END path1;

	 path2:	BEGIN 
		<code in preparation for the milestone>
		SIGNAL milestone;
		<code following the milestone>
		END path2
	COEND 
.REFILL

.NEWSSS STATEMENT CONDITION MONITORS

We have already seen condition monitors in the context of motion
statements.  The same construct is of general utility; most of
what was said before holds for the %4statement condition monitor%*
as well.

The conditions which may be tested in statement condition monitors
are principally events, since DURATION, SQUEEZE, and FORCE are
associated usually with a particular motion.  
As is the case with motion condition monitors, the statement condition
monitors can be in two states:  %4enabled%* and %4disabled%*. A monitor
becomes enabled when its defining statement is executed, and becomes
disabled when it triggers, is explicitly disabled by some other
statement, or its local block is exited.  The same conventions as
have already been seen apply to  the naming of condition monitors
and their explicit enabling and disabling.
Scope rules come into play regarding what condition monitors it
is permitted to enable or disable; the rule is that only condition
monitors defined locally or globally to a piece of code can be
touched by that code.
  The word DEFER still
causes a condition monitor to be defined in an initially disabled
state.

When a block is exited, all monitors local to that block are disabled.
However, the block exit code will wait until the bodies of any triggered
monitors are completed before disabling any monitors, deallocating local
variables, or performing any of the other functions associated 
with block termination.  If the execution of one of these triggered
monitor bodies causes other monitors to trigger, then the block
exit will wait for those, also.  Furthermore, block exit is treated
as an atomic process; all monitors are disabled at the same time.

The constructs CRITICAL and UNCRITICAL apply to statement condition
monitors just as they do to motion condition monitors.

.NEWSSS	COMMENTS

	The most standard way to insert comments in an AL program
is to surround them with curly brackets, as we have done in all
our examples so far.  It is also legal to use 
the word COMMENT before a comment, and to end it
by a semicolon.  This type of comment may not contain any semicolon.
The user can optionally reset the comment delimiters
from "α{α}" to whatever she wishes, by means of a require statement
such as
.UNFILL
	REQUIRE "α%α%" COMMENT_DELIMITERS       .
.REFILL
which would cause the scanner to ignore any text between "α%" signs.
It is expected that this will seldom be needed.

.NEWSSS	LABELS

	%4Labels%* specify points in the program; they are useful for
naming condition monitors, and subtasks.  It
also assists during debugging of programs.
To label a statement, preface it with an identifier followed by a colon.
Labels are not declared.
.UNFILL
	foo: a ← a + 1;
.REFILL

.NEWSSS ABORT

	Occasionally the user wishes to stipulate that if the program
ever reaches a particular point, something is hopelessly wrong.  The
statement ABORT causes the runtime to stop all moving devices and
to terminate execution.  The supervisor is informed of the halt, and
will inform the user. ABORT takes an optional string argument, which
is a message which will be given to the user if the ABORT statement
is executed.  An example:
.UNFILL
	ABORT ("I keep missing the hole!")
.REFILL

.NEWSSS OUTPUT

	There are several ways that the user can request output
from AL to the console.  As mentioned above, ABORT can print
a message during execution.  There is another way to print a
message during execution, the WRITE statement, which
takes as arguments a list of variables and constants.
It is also legal to include a string constant in this list (there
are no string variables in AL).  Formatting of output is automatic.
An example:
.UNFILL
	WRITE ("I think that the pump is at ",PUMP)
.REFILL

	Some pieces of code are only intended to work under
certain conditions of planning knowledge.  Such code might 
have a check to insure that its preconditions are met; if not,
it is proper to signal a compile-time error, with a message.
This is done with the PLAN ERROR statement, which optionally
takes a string argument, and which will halt compilation and print
the message.  One of the options the supervisor will give the user
is to proceed as if no error had been encountered.  Here is
an example:
.UNFILL
	PLAN ERROR("Hey!  You didn't attach the pump to the hand!")
.REFILL

	A similar statement which merely prints its message but
does not halt compilation is the PLAN WRITE statement, which
behaves in all respects like the runtime WRITE statement in that
it can take variables and constants in its argument list, but where
variables are specified, the planning values will be printed.  For
example:
.UNFILL
	PLAN WRITE("Yellow arm should be at",yellow)
.REFILL

.NEWSSS	PROCEDURES

	AL  has  only   a  limited  capacity  for   procedures.  All
parameters  to a procedure  assume the planning  value "undefined" at
the conclusion of a procedure  call, except those which are  declared
as VALUE parameters  in the procedure heading, or those  stated to be
UNCHANGED  in the procedure  call. There is no  safeguard against the
accidental   modification  of  "unchanged"   parameters;   to   state
"unchanged" is entirely equivalent to an assertion that the parameter
has not changed its value during the execution of the procedure.  The
declaration of a procedure is this:
.UNFILL
	 type PROCEDURE name (argument list)     ,
.REFILL
where  %4type%* is any data type (and  is optional), and %*argument list%*
is a list of parameter names with their types.  An example:
.UNFILL
	DISTANCE SCALAR PROCEDURE lgth (FRAME f1, f2; VECTOR VALUE v1);
.REFILL
This  declares that  lgth is a procedure which returns  a scalar, and
takes as arguments two frames and one vector.  The vector is not
changed by the procedure.

	To call such a procedure:
.UNFILL
	DISTANCE SCALAR s1;
	FRAME frob, hole;
	VECTOR vect;
	:
	s1 ← lgth(frob, UNCHANGED hole, vect);
.REFILL
This further asserts that hole is not changed by the call.

It is a good idea to use the planning value assignment ("α←α←")
heavily at the start of  a procedure body to
inform  the  compiler  of  the  values  to  expect  for  the  various
arguments. Remember that trajectories planned on the basis  of highly
inaccurate planning values will not work well.
As a procedure is entered,  all variables have planning value
"undefined".   Globals may be accessed,  but they also have undefined
initial  planning  value.   All  variables  which  have  explicit  or
implicit  assignments within a  procedure acquire  the value
"undefined" at the point directly after the procedure call.

	No modification  of the affixment structure  is allowed inside a
procedure. The  compiler (often wrongly)  assumes that  there are  no
affixments involving variables within a procedure; it requires an assertion
like
.UNFILL
	ASSERT FORM(AFFIXED, f1, f2)   .
.REFILL
to override this mistake.  Affixments are discussed in {ssref aff}
and more general assertions in {ssref asr}.

	There  are four  special  types  of procedure  calls:  A  AL
program might wish to call a routine coded for the mini or a routine
coded for the  timesharing machine.
 Likewise, a  program on the  timesharing computer may wish  to
control an AL program, or a routine on the  mini may wish to request
some arm motion.

	To  achieve the  first  two  cases,   there  exist  %4external
procedures%* in AL.  These are compiled into calls on either routines
in the mini or  routines in the timesharing computer's runtime package.  To  declare
such a  procedure: 
.UNFILL
	EXTERNAL MAXI FRAME PROCEDURE foo (FRAME a, b; VECTOR v)    .
.REFILL
 This declares the procedure foo to be a procedure resident
in the runtime "maxi" (that is, timesharing
computer) package,  expected to return a frame  value, and
taking as arguments two frames  and a vector. Maxi procedures do not
have access  to the  actual variables  sent, since  copies are  made;
therefore, all  arguments to  maxi procedures  are considered to  be
VALUE parameters.

	It  is  possible to  declare  untyped  (i.e., statement-like,
instead of expression-like) procedures as well.  Replace "maxi" with
"mini" for procedures in the  mini. Such procedures do have access
to  values, and therefore parameters are not automatically considered
to be VALUE.

	To achieve  the  second two  cases,   there  exist  %4internal
procedures%* in AL:
.UNFILL
	INTERNAL FORCE VECTOR PROCEDURE baz (SCALAR s);
.REFILL
Internal procedures  must be  at the  top
level of an AL program.   A complete AL program is  considered to be
an untyped procedure without parameters.